import json
import jsonss
from .error import JSONSSError

class _JSONSSServiceItem:

    def __init__ (self, it, name, urlname = ""):
        if (type(it) is not int) or (it not in [jsonss.JSONSS_SERVICE, jsonss.JSONSS_METHOD, jsonss.JSONSS_PROPERTY, jsonss.JSONSS_EVENT]):
            raise JSONSSError, (500, "Invalid interface item type")
        if ((type(name) is not str) and (type(name) is not unicode)) or (jsonss._namere.match(name) is None):
            raise JSONSSError, (500, "Invalid interface item name: " + name)
        if urlname == "":
            urlname = name
        if ((type(urlname) is not str) and (type(urlname) is not unicode)) or (jsonss._urlre.match(urlname) is None):
            raise JSONSSError, (500, "Invalid interface item URL-alias: " + urlname)
        self.t = it
        self.n = name
        self.u = urlname
        self.impl = None
        self.getter = None
        self.setter = None

    def simplify(self):
        if self.t == jsonss.JSONSS_SERVICE:
            return {"t": self.t, "n": self.n, "u": self.u, "i": self.impl._describe_interface()}
        else:
            return {"t": self.t, "n": self.n, "u": self.u}

class _JSONSSRequest:

    def __init__ (self, itempath, jsonnsmethod, text):
        self.path = itempath
        self.method = jsonnsmethod
        self.text = text
        if text == "":
            self.param = None
        else:
            self.param = json.loads(text)

class _JSONSSResponse:

    def __init__ (self):
        self.retval = None
        self.events = []

class JSONSSService:

    def __init__ (self):
        self._interface = {}
        self._events = []
        self.request = None
        self.response = None

    def _checknameconflict (self, name, urlname):
        for ik in self._interface.keys():
            if ik == urlname:
                raise JSONSSError, (500, "Interface item URL-alias altready exists: " + urlname)
            if self._interface[ik].n == name:
                raise JSONSSError, (500, "Interface item name altready exists: " + name)

    def add_service (self, name, urlname = "", service = None):
        if ((type(name) is not str) and (type(name) is not unicode)):
            raise JSONSSError, (500, "Invalid service item name")
        ii = _JSONSSServiceItem(jsonss.JSONSS_SERVICE, name, urlname)
        self._checknameconflict(ii.n, ii.u)
        ii.impl = service
        self._interface[ii.u] = ii

    def add_method (self, name, urlname = "", method = None):
        if ((type(name) is not str) and (type(name) is not unicode)):
            raise JSONSSError, (500, "Invalid service item name")
        ii = _JSONSSServiceItem(jsonss.JSONSS_METHOD, name, urlname)
        self._checknameconflict(ii.n, ii.u)
        ii.impl = method
        self._interface[ii.u] = ii

    def add_property (self, name, urlname = "", getter = None, setter = None):
        if ((type(name) is not str) and (type(name) is not unicode)):
            raise JSONSSError, (500, "Invalid service item name")
        ii = _JSONSSServiceItem(jsonss.JSONSS_PROPERTY, name, urlname)
        self._checknameconflict(ii.n, ii.u)
        ii.getter = getter
        ii.setter = setter
        self._interface[ii.u] = ii

    def add_event (self, name):
        if ((type(name) is not str) and (type(name) is not unicode)):
            raise JSONSSError, (500, "Invalid service item name")
        ii = _JSONSSServiceItem(jsonss.JSONSS_EVENT, name)
        self._checknameconflict(ii.n, ii.u)
        self._interface[ii.u] = ii

    def fire_event (self, name, data = None):
        if not self._interface.has_key(name) or (self._interface[name].t != jsonss.JSONSS_EVENT):
            return
            #or raise error?
        self._events += [{"n": name, "d": data}]

    def _dispatch (self, path, request, response):
        self._request = request
        self._response = response
        if (type(path) is not list) or (len(path) < 1) or ((type(path[0]) is not str) and (type(path[0]) is not unicode)):
            raise JSONSSError, (500, "Internal error, invalid dispatch path")
        item = path[0]
        newpath = path[1:]
        if not self._interface.has_key(item):
            raise JSONSSError, (500, "Unknown interface item URL-alias: " + item)
        if newpath != []:
            if self._interface[item].t != jsonss.JSONSS_SERVICE:
                raise JSONSSError, (500, "Interface item is not service, URL-alias: " + item)
            self.__dict__[self._interface[item].n]._dispatch(newpath, request, response)
        else:
            if self._interface[item].t == jsonss.JSONSS_SERVICE:
                if request.method != jsonss.JSONSS_METHOD_PING:
                    raise JSONSSError, (500, "Invalid JSONSS method: " + request.method)
                if not self._interface[item].impl:
                    raise JSONSSError, (500, "Service not implemented")
                self._interface[item].impl._request = request
                self._interface[item].impl._response = response
                self._interface[item].impl.ping()
            elif self._interface[item].t == jsonss.JSONSS_METHOD:
                if request.method != jsonss.JSONSS_METHOD_CALL:
                    raise JSONSSError, (500, "Invalid JSONSS method: " + request.method)
                if not self._interface[item].impl:
                    raise JSONSSError, (500, "Method not implemented")
                response.retval = self._interface[item].impl(request.param)
            elif self._interface[item].t == jsonss.JSONSS_PROPERTY:
                if request.method == jsonss.JSONSS_METHOD_GET:
                    if not self._interface[item].getter:
                        raise JSONSSError, (500, "No getter for property: " + self._interface[item].n)
                    response.retval = self._interface[item].getter();
                elif request.method == jsonss.JSONSS_METHOD_SET:
                    if not self._interface[item].setter:
                        raise JSONSSError, (500, "No setter for property: " + self._interface[item].n)
                    self._interface[item].setter(request.param)
                    response.retval = None
                else:
                    raise JSONSSError, (500, "Invalid JSONSS method: " + request.method)
            else:
                raise JSONSSError, (500, "Request not allowed: " + self._interface[item].n)
            response.events = self._events

    def _describe_interface (self):
        return reduce(lambda res, k: res + [self._interface[k].simplify()], self._interface.keys(), [])
